Skip to content

Conversation

@XuehaiPan
Copy link
Contributor

Description

Fix #5971 (comment)

Suggested changelog entry:

  • Placeholder.

# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x030E00C1 // 3.14.0rc1
PyCriticalSection_BeginMutex(&cs, &mutex.mutex);
# else
_PyCriticalSection_BeginMutex(_PyThreadState_GET(), &cs, &mutex.mutex);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will compile on 3.13 without additional changes. _PyCriticalSection_BeginMutex is in an inline function in an internal-only header (pycore_critical_section.h).

I think we should use PyAPI_FUNC(void) _PyCriticalSection_BeginSlow(PyCriticalSection *c, PyMutex *m); instead. It's not inline, but you'll need to declare it above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we'll still have the race condition with py::make_key_iterator in 3.13 due to the critical section implementation behaving differently in 3.13, but otherwise it should preserve compatibility.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we'll still have the race condition with py::make_key_iterator in 3.13 due to the critical section implementation behaving differently in 3.13, but otherwise it should preserve compatibility.

I think that's OK. We just want to limp through enough to make the pybind11 v3.0.2 release without breaking what worked with Python 3.13t before.

@XuehaiPan XuehaiPan changed the title Add failback implementation of PyCriticalSection_BeginMutex for Python 3.13t Add fallback implementation of PyCriticalSection_BeginMutex for Python 3.13t Feb 2, 2026
@XuehaiPan XuehaiPan requested a review from henryiii as a code owner February 3, 2026 11:46
`_PyCriticalSection_BeginSlow` is a private CPython function not exported
on Linux. For Python < 3.14.0rc1, use direct `mutex.lock()`/`mutex.unlock()`
instead of critical section APIs.
@XuehaiPan XuehaiPan requested review from colesbury and rwgk February 3, 2026 13:10
@henryiii
Copy link
Collaborator

henryiii commented Feb 5, 2026

I think this hangs. I think we probably should do nothing on 3.13t, rather than trying to also have a lock?

@colesbury
Copy link
Contributor

What was the issue with _PyCriticalSection_BeginSlow?

Refactor pycritical_section into a unified class with internal version
checks instead of using a type alias fallback. Skip locking in
make_iterator_impl for Python < 3.14.0rc1 to avoid deadlock during
type registration, as pycritical_section cannot release the mutex
during Python callbacks without PyCriticalSection_BeginMutex.
@XuehaiPan
Copy link
Contributor Author

What was the issue with _PyCriticalSection_BeginSlow?

There is a linkage issue on Linux.

@pytest.mark.skipif(
sys.platform.startswith("emscripten"), reason="Requires loadable modules"
)
@pytest.mark.xfail(env.MUSLLINUX, reason="Flaky on musllinux", strict=False)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a known errata with the current fix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@XuehaiPan could you please add the URL to the reason?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

@colesbury
Copy link
Contributor

colesbury commented Feb 5, 2026

You would need to copy the forward declaration from Python (PyAPI_FUNC(void)). I don't think extern "C" is always sufficient because of symbol visibility:

https://github.com/python/cpython/blob/60403a5409ff2c3f3b07dd2ca91a7a3e096839c7/Include/internal/pycore_critical_section.h#L91-L92

But if you get the mutex working, that seems fine too

Copy link
Collaborator

@rwgk rwgk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@colesbury @XuehaiPan question about this comment:

#5981 (comment)

I'm not sure if that means we should still do something, or if we're fine with this PR as-is? (it looks good to me, with my rather superficial specific background)

@pytest.mark.skipif(
sys.platform.startswith("emscripten"), reason="Requires loadable modules"
)
@pytest.mark.xfail(env.MUSLLINUX, reason="Flaky on musllinux", strict=False)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@XuehaiPan could you please add the URL to the reason?

@XuehaiPan
Copy link
Contributor Author

I'm not sure if that means we should still do something, or if we're fine with this PR as-is? (it looks good to me, with my rather superficial specific background)

Neither PyAPI_FUNC(void) nor extern "C" is working (#5981 (comment)).

$ cmake --build build --parallel --target pytest
...
[100%] Built target pybind11_tests
Traceback (most recent call last):
  File "/home/PanXuehai/Projects/pybind11/tests/conftest.py", line 26, in <module>
    import pybind11_tests
ImportError: /home/PanXuehai/Projects/pybind11/build/tests/pybind11_tests.cpython-313t-x86_64-linux-gnu.so: undefined symbol: _ZN8pybind116detail28_PyCriticalSection_BeginSlowEP17PyCriticalSectionP7PyMutex
ImportError while loading conftest '/home/PanXuehai/Projects/pybind11/tests/conftest.py'.
../../tests/conftest.py:26: in <module>
    import pybind11_tests
E   ImportError: /home/PanXuehai/Projects/pybind11/build/tests/pybind11_tests.cpython-313t-x86_64-linux-gnu.so: undefined symbol: _ZN8pybind116detail28_PyCriticalSection_BeginSlowEP17PyCriticalSectionP7PyMutex
gmake[3]: *** [tests/CMakeFiles/pytest.dir/build.make:76: tests/CMakeFiles/pytest] Error 4
gmake[2]: *** [CMakeFiles/Makefile2:601: tests/CMakeFiles/pytest.dir/all] Error 2
gmake[1]: *** [CMakeFiles/Makefile2:608: tests/CMakeFiles/pytest.dir/rule] Error 2
gmake: *** [Makefile:281: pytest] Error 2

@XuehaiPan XuehaiPan requested review from colesbury and rwgk February 9, 2026 10:37
Copy link
Collaborator

@rwgk rwgk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at the changes myself, and with Cursor. This is a great pragmatic response to our current situation. I'll merge this PR now.

@rwgk rwgk merged commit 3ae5a17 into pybind:master Feb 10, 2026
89 checks passed
@github-actions github-actions bot added the needs changelog Possibly needs a changelog entry label Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs changelog Possibly needs a changelog entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants